package com.coder4j.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassScanUtil {

    private static final Logger log = LoggerFactory.getLogger(ClassScanUtil.class);

    public static List<Class> getClassList(String path,String packageName) throws Exception {
        // file:/data/java/keller-server-2.0.1.jar!/BOOT-INF/classes!/
//        return getClassList(packageName);
        if(StringUtils.isEmpty(path) || !path.contains(".jar")){
            return getClassList(packageName);
        }
        int index = path.contains("!") ? path.indexOf("!") : path.length();
        path = path.substring(0,index).replace("file:","");
        return scanJarFile(path,packageName);
    }


    public static List<Class> getClassList(String packageName) throws Exception {
        List<Class> classList = new ArrayList<>();
        Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packageName.replaceAll("\\.", "/"));
        while (urls.hasMoreElements()) {
            URL url = urls.nextElement();
            if (url != null) {
                String packagePath = url.getPath();
                log.info("packagePath ===== {}",packagePath);
                addClass(classList, packagePath, packageName);
            }
        }
        return classList;
    }

    private static void addClass(List<Class> classList, String packagePath, String packageName) {
        try {
            File[] files = getClassFiles(packagePath);
            if (files != null) {
                for (File file : files) {
                    String fileName = file.getName();
                    if (file.isFile()) {
                        String className = getClassName(packageName, fileName);
                        classList.add(Class.forName(className));
                    } else {
                        String subPackagePath = getSubPackagePath(packagePath, fileName);
                        String subPackageName = getSubPackageName(packageName, fileName);
                        addClass(classList, subPackagePath, subPackageName);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static File[] getClassFiles(String packagePath) {
        return new File(packagePath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
            }
        });
    }

    private static String getClassName(String packageName, String fileName) {
        String className = fileName.substring(0, fileName.lastIndexOf("."));
        if (StringUtils.notEmpty(packageName)) {
            className = packageName + "." + className;
        }
        return className;
    }

    private static String getSubPackagePath(String packagePath, String filePath) {
        String subPackagePath = filePath;
        if (StringUtils.notEmpty(packagePath)) {
            subPackagePath = packagePath + "/" + subPackagePath;
        }
        return subPackagePath;
    }

    private static String getSubPackageName(String packageName, String filePath) {
        String subPackageName = filePath;
        if (StringUtils.notEmpty(packageName)) {
            subPackageName = packageName + "." + subPackageName;
        }
        return subPackageName;
    }


    public static List<Class> scanJarFile(String jarPath, String packagePath) throws Exception {

        log.info("scanJarFile == {},{}",jarPath,packagePath);

        List<Class> list = new ArrayList<>();
        // 得到 jar 包的位置

        JarFile jarFile = new JarFile(jarPath);
        List<String> packageList = new ArrayList<>();
        packageList.add(packagePath);
        Enumeration<JarEntry> ee = jarFile.entries();
        packagePath = packagePath.replace(".", "/");
        while (ee.hasMoreElements()) {
            JarEntry entry = ee.nextElement();
            String entryName = entry.getName();
            //BOOT-INF/classes/com/coder4j/exam/enums/AnswerStatusEnums.class
//            log.info("====000==={}", entryName);
            if (!entryName.contains(packagePath + "/") || !entryName.endsWith(".class") || entryName.contains("$")) {
                continue;
            }
            log.info("======={}", entryName);

            String className = entryName.substring(entryName.indexOf(packagePath)).replace("/", ".").replace(".class","");
            list.add(Class.forName(className));
        }

        return list;

    }
}
